home *** CD-ROM | disk | FTP | other *** search
- /* extarct.c - extract files from (tape) archive.
- * This is a part of the Tar program (see file tar.c)
- * Author: T.V.Shaporev
- * Creation date: 14 Dec 1990
- */
- #include <stdio.h>
-
- #include "sysup.h"
- #include "nodedef.h"
- #include "modern.h"
- #ifdef MODERN
- # include <string.h>
- #else
- char *strncpy();
- int strlen();
- #endif
- #ifndef MSDOS
- int mknod(), chown(), utime();
- long time();
- #endif
-
- #include "zippipe.h"
- #include "lzwbits.h"
- #include "lzwhead.h"
- #include "compress.h"
- #include "define.h"
- #include "lzpack.h"
-
- static int soctus __ARGS__(( register char *, register short* ));
- int soctul __ARGS__(( register char *, register long * ));
- static int mismatch __ARGS__(( register char *, register char *, int ));
-
- #define octal(c) (((c)&0370)=='0')
-
- static char unknown[] = "Tar: \'%s\' unknown file type \'%c\'\n";
- #define _unknown (unknown+9)
-
- static int soctus(s, u)
- register short *u;
- register char *s;
- {
- register i;
- while (*s == ' ') ++s;
- for (*u=0, i=0; octal(*s) && i<7; i++, s++) *u = (*u<<3)|(*s&7);
- return *s!=' ' && *s!='\0';
- }
-
- int soctul(s, u)
- register long *u;
- register char *s;
- {
- register i;
- while (*s == ' ') ++s;
- for (*u=0, i=0; octal(*s) && i<11; i++, s++) *u = (*u<<3)|(*s&7);
- return *s!=' ' && *s!='\0';
- }
-
- int gethead()
- {
- short n;
- static short errcount = 0;
- register char *err_text = "Tar: bad directory structure\n";
-
- if ((hblock = readtape()) == NULL) return ERROR;
- if ((hblock->name[0]) == '\0') {
- return errcount ? (++errcount, ERROR) : FALSE;
- }
- if (soctus(hblock->chksum, &n)) goto bad;
- if (n != headsum(hblock)) {
- err_text = "Tar: directory checksum error\n"; goto bad;
- }
- if (soctus(hblock->mode, (short*)&(st.st_mode)) ||
- soctus(hblock->uid, (short*)&(st.st_uid)) ||
- soctus(hblock->gid, (short*)&(st.st_gid)) ||
- soctul(hblock->size, (long *)&(st.st_size)) ||
- soctul(hblock->mtime, (long *)&(st.st_mtime))) goto bad;
- if (hblock->filetype == TF_CHR || hblock->filetype == TF_BLK) {
- if (soctus(hblock->x.new.devmajor, &dmajor) ||
- soctus(hblock->x.new.devminor, &dminor)) goto bad;
- }
- if (errcount != 0) {
- (void)fprintf(myout,
- "Tar: %d blocks skipped to find header\n", errcount);
- errcount = 0;
- }
- if (hblock->filetype == TF_OLD || hblock->filetype == TF_REG) {
- (void)soctul(hblock->x.old.srclen, &codesize); /* no sence for */
- (void)soctul(hblock->x.old.srcsum, &longcsum); /* non-packed file */
- } else {
- longcsum = codesize = 0;
- }
- return TRUE;
- bad:
- if (errcount++ == 0) (void)fprintf(myout, err_text);
- if (!i_flag) done(ERREAD);
- return ERROR;
- }
-
- static int tstfield __ARGS__(( char *, int ));
-
- static int tstfield(s,n) /* is the field a valid octal number? */
- char *s; int n;
- {
- register j;
-
- for (j=0; j<n && octal(s[j]); j++);
- if (!j || j >= n) return FALSE;
- if (s[j] == ' ') ++j;
- while (j<n && !s[j++]);
- return j>=n;
- }
-
- #define TstField(x) tstfield(x, sizeof(x))
-
- short isextent(allx, allb)
- short *allx; long *allb;
- {
- short n;
-
- if ((hblock->filetype != TF_OLD && hblock->filetype != TF_REG) ||
- !TstField(hblock->x.s_v.extent) ||
- !TstField(hblock->x.s_v.allext) ||
- !TstField(hblock->x.s_v.total)) return ERROR;
- (void)soctus(hblock->x.s_v.extent, &n);
- (void)soctus(hblock->x.s_v.allext, allx);
- (void)soctul(hblock->x.s_v.total, allb);
- return n < 1 || n > *allx || *allb <= st.st_size ? ERROR : n;
- }
-
- int ismagic()
- {
- register i;
- register char *p, *q;
- static char magic_list[][8] = { TMAGIC, GMAGIC };
-
- if (hblock->filetype != TF_OLD) {
- for (i=0; i<dimof(magic_list); i++) {
- p = magic_list[i];
- q = hblock->x.new.magic;
- while (*q && *q == *p) {
- ++q; p++;
- }
- if (*q == '\0' && (*p == '\0' || *p == ' '))
- return magic_list[i][0];
- }
- }
- return 0;
- }
-
- char prefix()
- {
- switch (hblock->filetype) {
- case TF_CTG: /* ??? contiguous file */
- case TF_OLD:
- case TF_REG:
- case TF_LNK: return ' ';
- case TF_SYM: return 'l';
- case TF_CHR: return 'c';
- case TF_BLK: return 'b';
- case TF_DIR: return 'd';
- case TF_QUE: return 'p';
- case GF_DMP: return 'D';
- case GF_MUL: return ',';
- case GF_VOL: return 'v';
- }
- return '?';
- }
-
- int usize() /* is it valid to use file size in header */
- {
- switch (hblock->filetype) {
- case TF_OLD: case TF_REG: case TF_CTG:
- case GF_DMP: case GF_MUL: case GF_SPR: /* what's it? I wonder */
- return TRUE;
- }
- return FALSE;
- }
-
- void skipfile()
- {
- register long blocks;
-
- for (blocks=(st.st_size+BLKSIZE-1)/BLKSIZE; blocks>0; blocks--) {
- if (readtape() == NULL) {
- (void)fprintf(myout, "Tar: tape read error\n");
- if (i_flag) done(ERREAD);
- return;
- }
- }
- }
-
- static int mismatch(p, s, l)
- register char *p, *s; int l;
- {
- register i;
-
- for (i=0; *p && i<l; ++p, i++) {
- if (*p == '*') {
- while (*++p == '*') ;
-
- while (l>=i) {
- if (!mismatch(p, s+i, l-i)) return FALSE;
- ++i;
- }
- return TRUE;
- } else if (*p != '?') {
- if (s[i] != *p) return ERROR;
- }
- }
- return *p || i<l;
- }
-
- int inargs(argc, argv, n)
- int argc; register char *argv[], *n;
- {
- register i; register j; register k;
- register char *p;
-
- for (i=0; i<argc; i++) {
- if (s_flag) {
- for (p=argv[i], j=0; j<MAXTNAME && p[j]==n[j] && p[j]!=0; j++);
- if (j<MAXTNAME && p[j]==0 && (n[j]==0 || n[j]=='/')) return TRUE;
- } else {
- j = 0;
- while (j<MAXTNAME && n[j]) {
- do ++j; while (n[j]!='/' && n[j]!=0);
- k = mismatch(argv[i], n, j);
- if (k == ERROR) goto extloop;
- if (k == FALSE) return TRUE;
- }
- }
- extloop:;
- }
- return FALSE;
- }
-
- void scantape(argc, argv, handler)
- int argc; char *argv[]; void (*handler)__ARGS__((void));
- {
- register k;
-
- while ((k=gethead()) != FALSE) {
- if (k == ERROR) continue;
- if (argc < 1 || inargs(argc, argv, hblock->name)) {
- (*handler)();
- } else {
- if (usize()) skipfile();
- }
- }
- if (pktype == PKZIP) {
- while ((k=unzread((char*)hblock, BLKSIZE)) == BLKSIZE);
- if (k != ERROR) {
- if (k) (void)fprintf(myout, "Tar: final block misaligned\n");
- k = unzclose();
- }
- if (k) {
- register char *p = NULL;
- if (k == -1) p = "error"; else if (v_flag) p = "warning";
- if (p) (void)fprintf(myout, "Tar: unzip %s: %s\n",
- p, ziperrlist[ziperror]);
- }
- }
- }
-
- extern long thisread;
- extern int arcget __ARGS__(( void ));
-
- void catalog()
- {
- register long thislen;
- register reverse = FALSE, skipped = FALSE;
- register char *p;
- static no_mem = FALSE;
- short nx = 1, allx; long xinfo;
- extern char ofname[];
- register c;
-
- p = hblock->name;
- c = hblock->filetype;
-
- if (v_flag) prmode(prefix(), (int)(st.st_mode));
- if ((c == TF_OLD || c == TF_REG) && (nx=isextent(&allx, &xinfo)) < 1) {
- if (st.st_size <= codesize) {
- reverse = TRUE;
- } else if (pktype == PKfLZW) {
- register i, j;
-
- i = strlen(hblock->name);
- if (hblock->name[--i] == 'Z' && hblock->name[--i] == '.') {
- p = strncpy(ofname, hblock->name, MAXTNAME);
- (void)z_getmem(BITS);
- codesize = 0; thisread = 0;
- if ((j = dbegin(arcget)) == 0) {
- do {
- if ((j = dpiece(pk_out, pksize)) > 0) codesize += j;
- } while (j == pksize);
- skipped = TRUE;
- } else if (j > 0) {
- bacouple(); /* file is not in compressed format */
- } else if (!no_mem) {
- (void)fprintf(myout, "Tar: not enough memory to uncompress\n");
- no_mem = TRUE;
- }
- }
- }
- thislen = codesize > st.st_size ? codesize : st.st_size;
- } else {
- thislen = st.st_size;
- }
- if (v_flag) {
- (void)fprintf(myout, " %3d/%1d ", st.st_uid, st.st_gid);
- if (c == TF_CHR || c == TF_BLK) {
- (void)fprintf(myout,
- pkfile ? "%10d,%-5d " : "%3d,%-3d ", dmajor, dminor);
- } else {
- (void)fprintf(myout, "%7ld ", reverse ? thislen : st.st_size);
- if (pkfile) {
- if ((c == TF_OLD || c == TF_REG) &&
- st.st_size <= codesize) {
- (void)fprintf(myout, "(%7ld) ",
- reverse ? st.st_size : codesize);
- } else {
- (void)fprintf(myout, " ");
- }
- }
- }
- }
- (void)fprintf(myout, "%-.*s", MAXTNAME, p);
-
- switch (c) {
- case TF_LNK:
- case TF_SYM:
- if (v_flag) (void)fprintf(myout, "\n");
- (void)fprintf(myout, " %s to %s\n",
- c == TF_SYM ? "symlink" : "linked",
- hblock->linkname);
- break;
- case TF_OLD:
- case TF_REG:
- if (nx >= 1) {
- if (v_flag) (void)fprintf(myout, "\n");
- (void)fprintf(myout, " [extent #%d of %d]", nx, allx);
- if (v_flag) (void)fprintf(myout, " %ld bytes total", xinfo);
- }
- case TF_CHR: case TF_BLK:
- case TF_DIR: case TF_QUE: case TF_CTG:
- case GF_DMP: case GF_VOL:
- (void)fprintf(myout, "\n");
- break;
- case GF_MUL:
- if (v_flag) (void)fprintf(myout, "\n");
- (void)soctul(hblock->x.new.offset, &xinfo);
- (void)fprintf(myout, "[from %ld to %ld]",
- xinfo, xinfo+st.st_size-1);
- (void)fprintf(myout, "\n");
- break;
- default:
- if (v_flag) (void)fprintf(myout, "\n");
- (void)fprintf(myout, _unknown, c);
- }
- if (nx < 1 && v_flag && j_flag && /*dummy*/!skipped &&
- hblock->x.old.comment[0] && !ismagic()) {
- (void)fprintf(myout, "> %s\n", hblock->x.old.comment);
- }
- if (usize()) {
- if (!skipped) skipfile();
- allbytes += thislen;
- }
- ++allfiles;
- }
-
- static char *cutname __ARGS__((register char *p));
-
- static char *cutname(p)
- register char *p;
- {
- register j;
-
- if (nonest) {
- j = strlen(p);
- while (j>0 && p[j-1] != '/'
- #ifdef MSDOS
- && p[j-1] != ':'
- #endif
- ) --j;
- p += j;
- } else {
- #ifdef MSDOS
- if (deldrv && p[1] == ':' &&
- (p[0]>='A' && p[0]<='Z' || p[0]>='a' && p[0]<='z'))
- p += 2;
- #endif
- if (dslash && *p == '/') ++p;
- }
- return p;
- }
-
- void extract()
- {
- register j, k;
- register char *p;
- extern int makedir __ARGS__((char *, int));
- extern int testdir __ARGS__((char *));
-
- p = cutname(hblock->name);
- if (u_flag) {
- struct stat s;
-
- if (stat(p, &s)==0 && s.st_mtime >= st.st_mtime) {
- if (usize()) skipfile(); return;
- }
- }
- if (w_flag && !okwork('x', prefix(), &st, p)) {
- if (usize()) skipfile(); return;
- }
- if ((j=strlen(p)-1) >= 0 && p[j] == '/') {/* directory with permissions */
- if (testdir(p) != TRUE) return;
- p[j] = '\0';
- } else if (hblock->filetype == TF_DIR || hblock->filetype == GF_DMP) {
- k = FALSE;
- if (makedir(p, FALSE) != 0) {
- if (testdir(p) != TRUE || makedir(p, TRUE) != 0) k = TRUE;
- }
- if (usize()) skipfile();
- if (k) return;
- } else if (hblock->filetype == TF_LNK) {
- makelink(p, cutname(hblock->linkname)); return;
- } else if (hblock->filetype == TF_OLD || hblock->filetype == TF_REG) {
- if (restore(p) != 0) return;
- #ifdef UNIX
- } else if (hblock->filetype == TF_CHR || hblock->filetype == TF_BLK ||
- hblock->filetype == TF_QUE) {
- st.st_mode &= 07777;
- if (hblock->filetype != TF_QUE) {
- st.st_mode |= hblock->filetype == TF_BLK ? S_IFBLK : S_IFCHR;
- st.st_rdev = makedev(dmajor, dminor);
- } else {
- st.st_mode |= S_IFIFO;
- st.st_rdev = 0;
- }
- j = 0;
- k = FALSE;
- do {
- if (mknod(p, st.st_mode, st.st_rdev) == 0) break;
- } while (++j < 2 && (k = testdir(p)) == TRUE);
- if (j > 1) (void)fprintf(myout, "Tar: can\'t create \'%s\'\n", p);
- if (j > 1 || k == ERROR) return;
- if (v_flag) (void)fprintf(myout, "x %s\n", p);
- #endif
- } else {
- (void)fprintf(myout, unknown, p, hblock->filetype);
- return;
- }
- #ifdef UNIX
- if (!o_flag) (void)chown(p, (int)st.st_uid, (int)st.st_gid);
- if (!m_flag) {
- long t[2];
-
- t[0] = time(t);
- t[1] = st.st_mtime;
- (void)utime(p, t);
- }
- #endif
- }
-
- void uplist()
- {
- register struct node *this; struct node *prev;
-
- if ((this = finditem(hblock->name, &prev, timehead)) == NONE) {
- if ((this = additem(hblock->name, prev, &timehead)) == NONE) {
- outmem(myout);
- }
- this->info.time = st.st_mtime;
- } else {
- if (this->info.time < st.st_mtime) this->info.time = st.st_mtime;
- }
- }
-
- void acctime()
- {
- if (u_flag) uplist();
- if (usize()) skipfile();
- }